﻿using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Documents;

namespace DimensionsHelper.Client.WinUi.Helpers;

public class TextBindHelper
{
    public static readonly DependencyProperty InlineStyleProperty = DependencyProperty.RegisterAttached(
        "InlineStyle",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnInlineStylePropertyChanged));


    public static readonly DependencyProperty BaseTextStyleProperty = DependencyProperty.RegisterAttached(
        "BaseTextStyle",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnBaseTextStylePropertyChanged));

    
    public static readonly DependencyProperty BaseTextStyleWithoutFontWeightProperty = DependencyProperty.RegisterAttached(
        "BaseTextStyleWithoutFontWeight",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnBaseTextStyleWithoutFontWeightPropertyChanged));


    public static readonly DependencyProperty BaseRangeStyleProperty = DependencyProperty.RegisterAttached(
        "BaseRangeStyle",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnBaseRangeStylePropertyChanged));


    public static readonly DependencyProperty TextBlockAlignmentsProperty = DependencyProperty.RegisterAttached(
        "TextBlockAlignments",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnTextBlockAlignmentsPropertyChanged));


    public static readonly DependencyProperty TextBlockStyleProperty = DependencyProperty.RegisterAttached(
        "TextBlockStyle",
        typeof(ExcelRangeStyleViewModel),
        typeof(TextBindHelper),
        new PropertyMetadata(null, OnTextBlockStylePropertyChanged));


    public static void SetInlineStyle(DependencyObject d, ExcelRangeStyleViewModel value) =>
        d.SetValue(InlineStyleProperty, value);

    public static ExcelRangeStyleViewModel? GetInlineStyle(DependencyObject d) =>
        d.GetValue(InlineStyleProperty) as ExcelRangeStyleViewModel;


    private static void BindBaseFontStyleWithoutFontWeight(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        bool isTextBlock = d is TextBlock;

        BindingOperations.SetBinding(
            d,
            isTextBlock ? TextBlock.FontStyleProperty : TextElement.FontStyleProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.FontStyle)),
                Mode = BindingMode.OneWay
            });

        BindingOperations.SetBinding(
            d,
            isTextBlock ? TextBlock.TextDecorationsProperty : TextElement.TextDecorationsProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.TextDecoration)),
                Mode = BindingMode.OneWay
            });

        BindingOperations.SetBinding(
            d,
            isTextBlock ? TextBlock.ForegroundProperty : TextElement.ForegroundProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.Foreground)),
                Mode = BindingMode.OneWay
            });
    }


    private static void BindBaseFontStyleProperties(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        BindBaseFontStyleWithoutFontWeight(d, e);
        bool isTextBlock = d is TextBlock;
        BindingOperations.SetBinding(
            d,
            isTextBlock ? TextBlock.FontWeightProperty : TextElement.FontWeightProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.FontWeight)),
                Mode = BindingMode.OneWay
            });
    }


    private static void BindBaseRangeStyleProperties(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        bool isTextBlock = d is TextBlock;

        BindingOperations.SetBinding(d,
            isTextBlock ? TextBlock.FontFamilyProperty : TextElement.FontFamilyProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.FontFamily)),
                Mode = BindingMode.OneWay
            });

        BindingOperations.SetBinding(d,
            isTextBlock ? TextBlock.FontSizeProperty : TextElement.FontSizeProperty,
            new Binding
            {
                Source = e.NewValue,
                Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.PixelFontSize)),
                Mode = BindingMode.OneWay
            });
    }


    private static void BindBaseStyleProperties(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        BindBaseFontStyleProperties(d, e);
        BindBaseRangeStyleProperties(d, e);
    }


    private static void BindRangeAlignmentProperties(DependencyObject d, object source)
    {
        // HAlign
        BindingOperations.SetBinding(d, FrameworkElement.HorizontalAlignmentProperty, new Binding
        {
            Source = source,
            Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.HAlign)),
            Mode = BindingMode.OneWay
        });
        // VAlign
        BindingOperations.SetBinding(d, FrameworkElement.VerticalAlignmentProperty, new Binding
        {
            Source = source,
            Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.Valign)),
            Mode = BindingMode.OneWay
        });
        // TextWrapping
        BindingOperations.SetBinding(d, TextBlock.TextWrappingProperty, new Binding
        {
            Source = source,
            Path = new PropertyPath(nameof(ExcelRangeStyleViewModel.TextWrapping)),
            Mode = BindingMode.OneWay
        });
    }


    private static void OnInlineStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
        BindBaseStyleProperties(d, e);


    public static void SetBaseTextStyle(DependencyObject d, ExcelRangeStyleViewModel value) =>
        d.SetValue(BaseTextStyleProperty, value);


    public static ExcelRangeStyleViewModel? GetBaseTextStyle(DependencyObject d) =>
        d.GetValue(BaseTextStyleProperty) as ExcelRangeStyleViewModel;


    private static void OnBaseTextStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
        BindBaseFontStyleProperties(d, e);


    public static void SetBaseTextStyleWithoutFontWeight(DependencyObject d, ExcelRangeStyleViewModel value) =>
        d.SetValue(BaseTextStyleWithoutFontWeightProperty, value);


    public static ExcelRangeStyleViewModel? GetBaseTextStyleWithoutFontWeight(DependencyObject d) =>
        d.GetValue(BaseTextStyleWithoutFontWeightProperty) as ExcelRangeStyleViewModel;


    private static void OnBaseTextStyleWithoutFontWeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
        BindBaseFontStyleWithoutFontWeight(d, e);


    public static void SetBaseRangeStyle(DependencyObject d, ExcelRangeStyleViewModel value) =>
        d.SetValue(BaseRangeStyleProperty, value);


    public static ExcelRangeStyleViewModel? GetBaseRangeStyle(DependencyObject d) =>
        d.GetValue(BaseRangeStyleProperty) as ExcelRangeStyleViewModel;


    private static void OnBaseRangeStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
        BindBaseRangeStyleProperties(d, e);


    public static void SetTextBlockAlignments(DependencyObject d, ExcelRangeStyleViewModel value) =>
        d.SetValue(TextBlockAlignmentsProperty, value);


    public static ExcelRangeStyleViewModel? GetTextBlockAlignments(DependencyObject d) =>
        d.GetValue(TextBlockAlignmentsProperty) as ExcelRangeStyleViewModel;


    private static void
        OnTextBlockAlignmentsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
        BindRangeAlignmentProperties(d, e.NewValue);


    public static void SetTextBlockStyle(DependencyObject d, ExcelRangeStyleViewModel? value) =>
        d.SetValue(TextBlockStyleProperty, value);


    public static ExcelRangeStyleViewModel? GetTextBlockStyle(DependencyObject d) =>
        d.GetValue(TextBlockStyleProperty) as ExcelRangeStyleViewModel;


    private static void OnTextBlockStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        BindBaseStyleProperties(d, e);
        BindRangeAlignmentProperties(d, e.NewValue);
    }
}